import jieba
from jieba import posseg
import os
import json
import copy


class Predictor(object):
    def __init__(self):
        self.p1 = os.getcwd()
        self.p5 = 'add_word.txt'
        self.rule1 = ['由', '由于', '因', '因为', '是因为', '受益于', '随着']
        self.timew = ['季', '年', '月', '周', '日', '时', '分', '秒', '世纪', '天']
        self.areaMoveTag = ['主要是', '原因是', '认为', '以为', '受益于', '因', '是否有', '加上', '来自于', '的是', '由于', '鉴于',
                            '在于', '基于', '应对', '引起', '导致', '体现在', '抑制了', '盘出了', '类似', '引发', '为了',
                            '就会', '造成', '不排除', '随', '预计', '加速', '代表']
        self.cent = None  # 中心词
        self.text = None  # 短文本
        self.indt = None  # 中心词起始位置
        self.words = []   # 分词结果列表
        self.tags = []    # 分词结果对应词性列表
        self.indw = None  # 分词后中心词位置
        self.pucnt = [',', '。', '.', '；', '，', '?', '!', ':', '？', '：', ';']  # 分割标点
        self.loc = 0      # 记录位置关系规则的类别
        self.he = ['和', '与', '跟', '同', '及', '、', '或', '以及']  # 并列连词
        self.movew = ['会', '将', '有望', '有助于', '有利于', '可能', '仍', '能够', '会去', '在', '可以', '是', '且']  # 去除词成分
        self.add_words = True   # 标记用户词典是否已加载

    # 初始化，提取文本信息
    def ininfo(self, content: dict):
        if self.add_words:
            self.add_words = False
            with open(os.path.join(self.p1, self.p5), 'r', encoding='utf8') as fp:
                for line in fp.readlines():
                    ls = line.split()
                    if len(ls) == 0:
                        continue
                    elif ls[0] == '@' and len(ls) > 2:
                        jieba.suggest_freq(tuple(ls[1:]), True)
                    elif len(ls) == 1:
                        jieba.add_word(ls[0], freq=555, tag='n')
                        jieba.suggest_freq(ls[0], True)
                    elif len(ls) == 2:
                        jieba.add_word(ls[0], freq=555, tag=ls[1])
                        jieba.suggest_freq(ls[0], True)
                    elif len(ls) == 3:
                        jieba.add_word(ls[0], freq=ls[1], tag=ls[2])
                        jieba.suggest_freq(ls[0], True)
                    else:
                        print('###' * 20, "用户词典加载错误！", '###' * 20)
                        print('发生错误词条为：', line)
                        exit()
        if self.text is None:
            self.text = content['document'][0]['text']
        if self.cent is None:
            self.cent = content['qas'][0][0]['answers'][0]['text']
            self.indt = content['qas'][0][0]['answers'][0]['start']
        if len(self.text) < 1 or len(self.cent) < 1:
            print('###' * 20, "文本内容不存在，或中心词缺失！", '###' * 20)
            exit()
        elif self.text[self.indt:][:len(self.cent)] != self.cent:
            print('###' * 20, '中心词位置输入错误！', '###' * 20)
            exit()
        jieba.add_word(self.cent, freq=5000, tag='v')
        self.words, self.tags = [], []
        for word, tag in posseg.lcut(self.text):
            self.words.append(word)
            self.tags.append(tag)
        # 保证中心词分词准确
        for i, v in enumerate(self.words):
            if self.cent in v and self.cent != v:
                if len(''.join(self.words[:i])) <= self.indt <= len(''.join(self.words[:i])) + len(v):
                    tempi = v.index(self.cent)
                    if tempi > 0:
                        self.words[i] = v[:len(v) - len(self.cent)]
                        self.words.insert(i + 1, self.cent)
                        self.tags.insert(i + 1, 'v')
                    else:
                        self.words[i] = self.cent
                        self.words.insert(i + 1, v[len(self.cent):])
                        self.tags.insert(i + 1, 'v')

        for i, v in enumerate(self.words):
            if self.cent in v:
                if self.indt is not None and len(''.join(self.words[:i])) == self.indt:
                    self.indw = i
        self.loc = 0
        if any(True if c in self.cent else False for c in self.rule1):
            self.loc = 1

    # 数据预处理
    def preData(self):
        lx = '"\'“‘《<'
        rx = '"\'”’》>'
        dlx = '(（【[{｛「'
        drx = ')）】]}｝」'
        markm = [0, 0]
        words, tags = copy.deepcopy(self.words), copy.deepcopy(self.tags)
        while len(words)>0:
            if 'c'==tags[0] or words[0] in self.pucnt:
                self.indw -= 1
                del words[0]
                del tags[0]
            else:
                break
        if len(tags) > 0:
            ntags, nwords = [tags[0]], [words[0]]
            item = tags[0]
        else:
            return [], []
        count = 1
        for i, t in enumerate(tags):
            if count > 0:
                count -= 1
                continue
            if 'x' in item:
                if words[i - 1] in lx:
                    indx = lx.index(words[i - 1])
                    flag = rx[indx]
                    if flag in words[i:]:
                        for j, w in enumerate(words[i:]):
                            if flag == w:
                                count = j
                                break
                        if i+count-markm[0] < self.indw:
                            self.indw -= count+1
                            markm[0] += count+1
                        elif i-1-markm[0] < self.indw:
                            count = 0
                            nwords.append(words[i])
                            ntags.append(tags[i])
                            continue
                        for j in range(i, i + count + 1):
                            nwords[-1] += words[j]
                        ntags[-1] = 'n'
                    else:
                        nwords.append(words[i])
                        ntags.append(tags[i])
                elif words[i - 1] in dlx:
                    indx = dlx.index(words[i - 1])
                    flag = drx[indx]
                    if flag in words[i:]:
                        for j, w in enumerate(words[i:]):
                            if flag == w:
                                count = j
                                break
                        if count==1 and len(words[i])==1 and t!='x':
                            if i + count - markm[0] < self.indw:
                                self.indw -= count + 1
                                markm[0] += count + 1
                            elif i - 1 - markm[0] < self.indw:
                                count = 0
                                nwords.append(words[i])
                                ntags.append(tags[i])
                                continue
                            for j in range(i, i + count + 1):
                                nwords[-1] += words[j]
                            ntags[-1] = 'n'
                        else:
                            if i+count-markm[1]<self.indw:
                                self.indw -= count+2
                                markm[1] += count+2
                            elif i-1-markm[1] < self.indw:
                                count = 0
                                nwords.append(words[i])
                                ntags.append(tags[i])
                                continue
                            for j in range(i, i + count + 1):
                                nwords[-1] += words[j]
                            del nwords[-1]
                            del ntags[-1]
                            continue
                    else:
                        nwords.append(words[i])
                        ntags.append(tags[i])
                elif words[i - 1] in drx:
                    nwords.append(words[i])
                    ntags.append(tags[i])
                elif words[i - 1] == '、':
                    nwords.append(words[i])
                    ntags.append(tags[i])
                else:
                    nwords.append(words[i])
                    ntags.append(tags[i])
                if len(ntags) < 1:
                    nwords.append(words[i + count])
                    ntags.append(tags[i + count])
                    count += 1
                item = ntags[-1]
            else:
                item = t
                nwords.append(words[i])
                ntags.append(tags[i])
        return nwords, ntags

    # 根据中心词划分结果区域
    def getArea(self, words, tags):
        nspw = ['因', '果', '原', '情形', '情况', '程度']
        lx = '"\'“‘《<'
        rx = '"\'”’》>'
        dlx = '(（【[{｛「'
        drx = ')）】]}｝」'
        ind = self.indw
        if self.indw==0 or words[ind-1] in dlx+lx:
            print('-----------')
            if self.cent in self.rule1:
                self.loc = -1
            for i, c in enumerate(words):
                if c in self.pucnt:
                    ind = i
                    break
        # 中心词后部分
        flag = True
        while flag:
            if len(words) > ind+1 and '的' == words[ind + 1][0] and len(words[ind + 1]) > 1 \
                    and tags[ind + 1] not in ['j', 'i', 'l'] and 'n' not in tags[ind + 1]:
                words[ind + 1] = words[ind + 1][1:]
            if words[ind + 1] in lx:
                tempi = lx.index(words[ind + 1])
                if rx[tempi] in words[ind + 1:]:
                    flag = False
            if tags[ind + 1] == 'f' and len(words[ind + 1]) == 1:
                del words[ind + 1]
                del tags[ind + 1]
            if 'n' in tags[ind + 1] or tags[ind + 1] in ['a', 'b', 'd', 'v', 'j', 'i', 's', 'l', 'x', 'm', 'r', 'q', 'f']:
                break
            if flag:
                del words[ind + 1]
                del tags[ind + 1]
        indl = ind
        while True:
            indl += 1
            if len(tags) == indl + 1:
                break
            if words[indl + 1] in self.pucnt:
                break
            if tags[indl + 1] == 'c' and words[indl + 1] not in self.he or words[indl+1] == self.cent:
                break
        wordl = words[ind + 1: indl + 1]
        tagl = tags[ind + 1: indl + 1]

        # 中心词前部分
        flag = True
        while True:
            if ind < 1:
                break
            if ind > 1 and tags[ind - 1] == 'uj' and 'n' not in tags[ind - 2]:
                del words[ind - 1]
                del tags[ind - 1]
                ind -= 1
                del words[ind - 1]
                del tags[ind - 1]
                ind -= 1
            elif len(words[ind-1])<2 and ind>1 and (('c' in tags[ind - 2] and words[ind - 2] not in self.he) or words[ind - 2] in self.pucnt):
                del words[ind - 1]
                del tags[ind - 1]
                ind -= 1
            elif ('c' in tags[ind - 1] and words[ind - 1] not in self.he) or words[ind - 1] in self.pucnt:
                del words[ind - 1]
                del tags[ind - 1]
                ind -= 1
                break
            elif 'n' not in tags[ind - 1] and tags[ind - 1] not in ['v', 'a', 'l', 'j', 's']:
                del words[ind - 1]
                del tags[ind - 1]
                ind -= 1
            elif (tags[ind - 1] == 'a' or tags[ind - 1] == 'v' or any(True if c in words[ind - 1] else False for c in nspw)) and flag:
                n = 2
                while True:
                    if ind-n<0:
                        flag = False
                        break
                    if words[ind - n] in rx:
                        tempi = rx.index(words[ind - n])
                        if lx[tempi] in words[:ind - n]:
                            flag = False
                            break
                    if (tags[ind - n] in ['s', 'j', 'i', 'l', 'r'] and words[ind - n] not in self.pucnt) or 'n' in tags[
                        ind - n]:
                        flag = False
                        break
                    if words[ind - n] in self.pucnt or (
                            tags[ind - n] == 'c' and words[ind - n] not in self.he):
                        for i in range(n - 1):
                            del words[ind - 1]
                            del tags[ind - 1]
                            ind -= 1
                        break
                    else:
                        n += 1
            elif any(True if c in words[ind - 1] else False for c in self.movew):
                del words[ind - 1]
                del tags[ind - 1]
                ind -= 1
            else:
                break

        indp = ind
        while True:
            indp -= 1
            if indp < 1:
                break
            if words[indp - 1] in self.pucnt:
                break
            if (tags[indp - 1] == 'c' and words[indp - 1] not in self.he) or words[indp-1] == self.cent:
                break
        wordp = words[indp: ind]
        tagp = tags[indp: ind]
        wordpj = ''.join(wordp)
        templ = []
        for i, c in enumerate(self.areaMoveTag):
            if c in wordpj:
                tempi = -1
                for j in range(len(wordp)):
                    if c in wordp[::-1][j]:
                        tempi = len(wordp) - j - 1
                if tempi != -1:
                    if ('n' in tagp[tempi] and 'vn' not in tagp[tempi]) or tagp[tempi] in ['s', 'j', 'i', 'f', 'l']:
                        continue
                if any(True if t in tagp[tempi+1:] else False for t in ['n', 'r', 'j', 's', 'f']) \
                        and any(True if t in tagp[tempi+1:] else False for t in ['a', 'v', 'an', 'vn']):
                    templ.append(c)
        if len(templ) > 0:
            tempp = 0
            for item in templ:
                if len(wordpj) - wordpj[::-1].index(item[::-1]) > tempp:
                    tempp = len(wordpj) - wordpj[::-1].index(item[::-1])
            for i, item in enumerate(wordp):
                if tempp < 0:
                    break
                indp = i
                tempp -= len(item)
            wordp = wordp[indp:]
            tagp = tagp[indp:]
            if len(wordp)>0 and wordp[0]=='的':
                del wordp[0]
                del tagp[0]
                if len(tagp)>0 and ('n' in tagp[0] or tagp[0] in ['s', 'j', 'i', 'f', 'l', 'r']):
                    del wordp[0]
                    del tagp[0]
        if len(wordl)>0 and wordl[-1] in drx and tagl[-1]=='x':
            del wordl[-1]
            del tagl[-1]
        return wordp, tagp, wordl, tagl

    # 调整原因结果的成分位置
    def adjustloc(self, wordp, tagp, wordl, tagl):
        # 给、为句式带来的结果核心名词前置
        for i, t in enumerate(tagp[::-1]):
            if i > 0 and t in 'p' and wordp[::-1][i] in ['给', '为'] and 'v' not in tagp[::-1][:i]\
                    and (tagp[::-1][i-1] in ['s', 'j', 'i', 'f', 'l'] or 'n' in tagp[::-1][i-1]):
                nwordl = wordp[len(wordp) - i:]
                ntagl = tagp[len(wordp) - i:]
                nwordl.append('dvl')
                ntagl.append('dvl')
                nwordl.extend(wordl)
                ntagl.extend(tagl)
                wordp, tagp = wordp[:len(wordp)-i-1], tagp[:len(wordp)-i-1]
                if tagp[-1] == 'dvl':
                    del wordp[-1]
                    del tagp[-1]
                return wordp, tagp, nwordl, ntagl
        return wordp, tagp, wordl, tagl

    # 分词内容合并 1.连续名词合并；2.形容词+名词合并;3.词+‘地’合并成副词；4.副词+动词合并;等
    def merge(self, words, tags):
        noun = ['n', 'j', 'nr', 'nt', 'nz', 'an', 'eng', 'ng']
        if len(tags) > 0:
            ntags, nwords = [tags[0]], [words[0]]
            item = tags[0]
        else:
            return words, tags
        count = 1
        for i, t in enumerate(tags):
            if count > 0:
                if any(True if c in words[i] else False for c in ['将', '已', '都']):
                    item = 'dvl'
                    nwords[0] = 'dvl'
                    ntags[0] = 'dvl'
                count -= 1
                continue
            if any(True if str(c) in words[i] else False for c in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) and len(words[i])==1:
                tags[i] = 'm'
            t = tags[i]

            if item in noun and t in noun:
                ntags[-1] = 'n'
                nwords[-1] += words[i]
                item = 'n'
            elif item == 'an':
                ntags[-1] = 'n'
                item = t
                nwords.append(words[i])
                ntags.append(tags[i])
            elif words[i] in self.pucnt:
                continue
            elif 'x' in tags[i] and tags[i] != 'xuj' and words[i] != '、':
                nwords[-1] += words[i]
            elif 'm' == item and (('m' in tags[i] and all(True if c not in words[i] else False for c in self.timew)) or 'eng'==tags[i]):
                nwords[-1] += words[i]
            elif 'm' == item and 't' == tags[i]:
                nwords[-1] += words[i]
                ntags[-1] = 't'
            elif ('m' == item or 't' == item) and any(True if c in words[i] else False for c in self.timew) and len(
                    words[i]) < 3:
                nwords[-1] += words[i]
                if words[i - 1] == '/':
                    ntags[-1] = 'm'
                else:
                    ntags[-1] = 't'
            elif 'zg' == item and len(nwords[-1]) == 1 and ('t' == words[i] or 'm' in words[i]):
                nwords[-1] += words[i]
                ntags[-1] = tags[i]
            elif any(True if c in words[i] else False for c in ['将', '已', '都']):
                if 'dvl' not in nwords:
                    item = 'dvl'
                    nwords.append('dvl')
                    ntags.append('dvl')
            elif 'a' in item or 'd' in item and 'dvl' != item:
                if ('a' in item or 'd' in item) and words[i] == '的':
                    ntags[-1] = 'xuj'
                elif ('a' in item or 'd' in item) and tags[i] in noun:
                    ntags[-1] = 'ne'
                elif words[i] == '地':
                    ntags[-1] = 'd'
                elif 'v' in tags[i] and tags[i] != 'dvl':
                    ntags[-1] = 'v'
                else:
                    ntags[-1] = tags[i]
                nwords[-1] += words[i]
                item = ntags[-1]
            elif item == 'xuj' and tags[i] == 'xuj':
                nwords[-1] += words[i]
            else:
                item = t
                nwords.append(words[i])
                ntags.append(tags[i])
        return nwords, ntags

    # 词合并
    def merges(self, words, tags):
        lenth = len(tags)
        while lenth != len(self.merge(words, tags)[1]):
            words, tags = self.merge(words, tags)
            lenth = len(tags)
        return self.partOfDe(words, tags)

    # 词性结果调整与合并
    def adjTags(self, words, tags):
        for i, t in enumerate(tags):
            if t in ['n', 'j', 'nr', 'nt', 'nz', 'eng', 'ng']:
                tags[i] = 'n'
            if t in ['l', 'i']:
                tags[i] = 'vn'
            if 'u' in t and words[i] == '之':
                tags[i] = 'uj'
            if any(True if c in words[i] else False for c in ['多', '少', '大', '小']) and len(words[i]) < 3 and \
                    all(True if c not in tags[i] else False for c in ['n', 'r', 'v']):
                tags[i] = 'a'
                if len(tags) > i + 1:
                    words[i] += words[i + 1]
                    if 'n' == tags[i+1]:
                        tags[i] = 'ne'
                    else:
                        tags[i] = tags[i + 1]
                    del words[i + 1]
                    del tags[i + 1]
            if tags[i] == 'b' and len(tags) > i + 1:
                words[i] += words[i + 1]
                tags[i] = tags[i + 1]
                del words[i + 1]
                del tags[i + 1]
            if any(True if c in words[i] else False for c in ['到']) and len(words[i]) == 1:
                tags[i] = 'p'
            if any(True if c in words[i] else False for c in self.timew) and len(words[i]) < 3:
                if 'n' != tags[i] and 'v' not in tags[i]:
                    tags[i] = 't'
            if '自' == words[i]:
                tags[i] = 'p'
        if '后在' in words:
            i = words.index('后在')
            words[i] = words[i][0]
            tags[i] = 'f'
            words.insert(i+1, '在')
            tags.insert(i+1, 'p')
        return words, tags

    # 去除时间状语等成分；方位词|代词|时间词|数词
    def remove(self, words, tags):
        nwords, ntags = [], []
        count = 0
        words, tags = self.adjTags(words, tags)
        for i, t in enumerate(tags):
            if count > 0:
                count -= 1
                continue
            # 去除句首数词
            if 'm' in tags[i]and len(ntags) == 0 and len(words[i])>1:
                if len(ntags) > 0 and len(nwords[-1]) == 1 and ('v' in ntags[-1] or 'p' in ntags[-1]):
                    del ntags[-1]
                    del nwords[-1]
                if 'mq' != tags[i] and len(tags)>i+1 and words[i+1] != '人':
                    count += 1
                    if len(tags)>i+count+1 and 'f' in tags[i + count+1]:
                        count += 1
                continue
            # 去除时间方位词
            elif 'f' in tags[i]:
                fwords = ['前', '后', '中', '里', '内', '外', '期']
                if i>0 and 't' == tags[i-1] and any(True if c in words[i] else False for c in fwords):
                    continue
            elif any(True if c in words[i] else False for c in ['预期']) and len(tags)>i+1 and 't' == tags[i+1]:
                continue
            # 去除时间词
            elif 't' == tags[i] and (len(ntags)==0 or 'p' in ntags[0]):
                if len(ntags)>1 and '的' in nwords[-1]:
                    del nwords[-1]
                    del ntags[-1]
                    if len(ntags)>0 and words[i-1] == '的':
                        del nwords[-1]
                        del ntags[-1]
                    if len(ntags)>0 and 'p' in ntags[-1]:
                        del nwords[-1]
                        del ntags[-1]
                continue

            # 去指定除代词
            elif 'r' in tags[i] and len(ntags)==0:
                rwords = ['这', '些', '次', '此', '其', '每', '所']
                if any(True if c in words[i] else False for c in rwords):
                    continue

            # “在”，“从” 引到状语
            elif any(True if c in words[i] else False for c in ['在', '从', '由']) and 'p' in tags[i] and len(words[i+1:])>1:
                tempc = list(posseg.lcut(words[i])[-1])
                if len(tempc[0])==1:
                    if len(words) > i + 1 and any(True if c in tags[i:] else False for c in ['v', 'vn', 'i', 'l']):
                        count += 1
                        countn = 0
                        if len(words) > i + 2:
                            for j, c in enumerate(tags[i + 2:]):
                                if 'uj' in c:
                                    count += 1
                                    break
                                if len(tags[i+2:])>j+1 and tags[i+2:][j+1] == 'uj':
                                    count += 2
                                    break
                                if c in 'v' or (c == 'vn' and 'v' not in tags[i + 2:][j:]) or c in 'p':
                                    if len(words[i + 2:][j]) == 1 and all(True if c not in words[i + 2:][j] else False for c in ['有', '是']):
                                        count += 1
                                        break
                                    if 'n' not in ntags and 'vn' not in ntags and 'r' not in ntags and countn>0:
                                        count = countn + 1
                                    break
                                else:
                                    count += 1
                                    if 'n' in c:
                                        countn = count
                            continue
            elif words[i] in self.pucnt:
                continue
            elif any(True if c in words[i] else False for c in self.movew) \
                    and any(True if c in tags[i] else False for c in ['v', 'zg', 'p']):
                if len(ntags) > 0 and 'dvl' not in tags:
                    nwords.append('dvl')
                    ntags.append('dvl')
                continue
            nwords.append(words[i])
            ntags.append(tags[i])
        # 句首句末去除内容
        nwords, ntags = self.removebgend(nwords, ntags)
        nwords, ntags = self.tagsHe(nwords, ntags)
        return nwords, ntags

        # 句首句末成分处理与去除

    # 去除首末的部分词性词
    def removebgend(self, nwords, ntags):
        lenls = len(ntags)
        while lenls > 0:
            if ntags[0] in ['t', 'm', 'x', 'c']:
                if 'm' not in ntags[0] or (len(nwords[0]) > 1 and 'm' in ntags[0]):
                    del ntags[0]
                    del nwords[0]
            if len(ntags) > 1 and ntags[-1] in ['t', 'm', 'x', 'p', 'f', 'c']:
                if 'm' not in ntags[0] or (len(nwords[0]) > 1 and 'm' in ntags[0]):
                    del ntags[-1]
                    del nwords[-1]
                if len(ntags) > 0 and len(nwords[-1]) == 1 and ('v' in ntags[-1] or 'p' in ntags[-1]):
                    del ntags[-1]
                    del nwords[-1]
            if lenls == len(ntags):
                break
            else:
                lenls = len(ntags)
        if len(ntags) > 1 and nwords[-1] in ['局面', '事件', '原因', '希望', '问题', '有关']:
            del nwords[-1]
            del ntags[-1]
        if len(ntags) > 1 and '的' in nwords[-1] and 'n' not in ntags[-1]:
            if ntags[-1] == 'xuj':
                nwords[-1] = nwords[-1][:len(nwords[-1]) - 1]
            else:
                del nwords[-1]
                del ntags[-1]
        elif len(ntags) > 1 and '的' == nwords[0]:
            del nwords[0]
            del ntags[0]
        # 首位单字介词或动词去除
        if len(nwords) > 0 and ((len(nwords[0]) == 1 and ntags[0] == 'v') or ntags[0] == 'p'):
            flag = False
            if 'uj' not in ntags and 'xuj' not in ntags:
                flag = True
            else:
                inde = []
                for i, t in enumerate(ntags):
                    if 'uj' in t:
                        inde.append(i)
                if len(ntags) > inde[-1] + 1 and 'n' in ntags[inde[-1] + 1] and 'v' in ntags[inde[-1]:]:
                    flag = False
                else:
                    flag = True
            if flag:
                del nwords[0]
                del ntags[0]
        return nwords, ntags

    # “的”成分分析
    def partOfDe(self, words, tags):
        nwords, ntags = [], []
        count = 0
        for i, v in enumerate(words):
            if count > 0:
                count -= 1
                continue
            if len(tags) > i + 1 and '的' in v and v[-1] == '的' and all(
                    True if c not in words[i + 1:] else False for c in self.he):
                if tags[i] == 'xuj':
                    if i > 0 and tags[i - 1] == 'n':
                        if 'dvl' not in tags:
                            words.insert(i, 'dvl')
                            tags.insert(i, 'dvl')
                        return words, tags
                elif all(True if c not in tags[:i-1] else False for c in ['v', 'p']):
                    if i > 1 and any(True if c in tags[:i-1] else False for c in ['n', 'vn', 'r']) \
                            and ('v' in tags[i:] or 'vn' in tags[i:]):
                        if 'dvl' not in tags:
                            words[i] = 'dvl'
                            tags[i] = 'dvl'
                        return words, tags
                    for c in tags[i + 1:]:
                        if c == 'n':
                            break
                        if c in ['v', 'vn'] and 'a' not in tags[-1] and all(True if c not in tags[:i-2] else False for c in ['v', 'vn', 'p']):
                            if 'dvl' not in tags:
                                words[i] = 'dvl'
                                tags[i] = 'dvl'
                            return words, tags
                if len(nwords) > 0 and tags[i] != 'xuj':
                    nwords[-1] += words[i] + words[i + 1]
                    ntags[-1] = 'n'
                    count += 1
                elif tags[i] == 'xuj':
                    nwords.append(words[i] + words[i + 1])
                    ntags.append(tags[i + 1])
                    count += 1
            elif len(tags) > i + 2 and tags[i] == 'xuj' and 'v' in tags[i + 2:]:
                nwords.append(words[i] + words[i + 1])
                ntags.append('n')
                count += 1
            else:
                ntags.append(tags[i])
                nwords.append(words[i])
        return nwords, ntags

    # （和与及同）的连词与介词词性确定
    def tagsHe(self, words, tags):
        locs = [i for i, w in enumerate(words) if w in self.he]
        cmps = ['有', '存在', '相', '较']
        if len(locs)>0:
            for indl in locs:
                tags[indl] = 'c'
            for i, w in enumerate(words[locs[-1]:]):
                if '等' in w:
                    break
                if any(True if c in w else False for c in cmps) and 'v' in tags[locs[-1]:][i]:
                    tags[locs[-1]] = 'p'
        return words, tags

    # 并列成分分割成多句，['和', '与', '跟', '同', '及', '以及', '、', '或']
    def devivedSentence(self, words, tags):
        locs = [i for i, w in enumerate(words) if w in self.he]
        nwords, ntags = copy.deepcopy(words), copy.deepcopy(tags)
        partws, partts, segf = [], [], []
        p1, p2 = [], []
        if '等' in words:
            inde = words.index('等')
            nwords = nwords[:inde]
            ntags = ntags[:inde]
        if len(locs) > 0:
            bg = 0
            for ind in locs:
                partws.append(nwords[bg:ind])
                partts.append(ntags[bg:ind])
                segf.append(nwords[ind])
                bg = ind+1
            partws.append(nwords[bg:])
            partts.append(ntags[bg:])
            if 'dvl' in partts[-1]:
                i = 0
                for w,t in zip(partws, partts):
                    if 'uj' in t or 'xuj' in t:
                        partws[i], partts[i] = self.partOfDe(w, t)
                    i += 1
            # 后缀修饰
            if '的' in ''.join(partws[-1]) and '的' not in ''.join(partws[-2]):
                return self.devivedComp(words, tags)
            # 修饰前缀
            if '的' in ''.join(partws[0]) and '的' not in ''.join(partws[1]):
                return self.devivedComp(words, tags)
            res = []
            for i, pw in enumerate(partws):
                res.append(self.devivedComp(pw, partts[i]))
            for item in res:
                p1.append(item[0])
                p2.append(item[1])
        return [';'.join(p1), ';'.join(p2)]

    # 成分划分提取
    def devivedComp(self, words, tags):
        if len(words) < 1:
            return ['', '']
        lx = '"\'“‘《<'
        rx = '"\'”’》>'
        if 'dvl' in tags:
            indx = tags.index('dvl')
            p2, tag2 = words[indx + 1:], tags[indx + 1:]
        else:
            if 'v' in tags:
                indx = tags.index('v')
                if len(tags) > indx + 1 and '的' in words[indx + 1] and 'v' in tags[indx + 1:] and 'n' in tags[indx + 1]:
                    indx = indx + 1 + tags[indx + 1:].index('v')
                if 'p' in tags[:indx]:
                    for i, t in enumerate(tags[:indx]):
                        if 'p' in t and 'n' in tags[:i]:
                            indx = i
            elif 'a' in tags[-1]:
                indx = len(tags) - 1
            elif 'ne' in tags and tags[0]=='n':
                indx = tags.index('ne')
            elif 'p' in tags:
                indx = tags.index('p')
            elif 'vn' in tags:
                indx = tags.index('vn')
            elif 'd' in tags[-1]:
                indx = len(tags) - 1
            else:
                indx = len(tags)
            p2, tag2 = words[indx:], tags[indx:]
        p1, tag1 = words[:indx], tags[:indx]
        # 去独立引号
        if len(p1) == 1 and len(p1[0]) > 0 and p1[0][0] in lx and p1[0][-1] in rx:
            p1[0] = p1[0][1:len(p1[0]) - 1]
        # 去单字动词
        if len(p2) == 1 and 'v' in tag2[0] and len(p2[0]) == 1:
            del p2[0]
        # 去独立代词
        if len(p1) == 1 and 'r' in tag1[0]:
            p1 = ''
        # 去核心名词后的时间词
        while len(p1) > 0:
            if 't' == tag1[-1] or 'c' in tag1[-1] or 'm' in tag1[-1]:
                del tag1[-1]
                del p1[-1]
            else:
                break
        # p1 为空,且p2仅有一个'vn'时，p1,p2互换
        if len(p1) == 0 and len(p2) == 1 and tag2[0] == 'vn':
            p1, tag1 = p2, tag2
            p2, tag2 = [], []
        # 去除句中的方位词p1
        if 'f' in tag1[1:]:
            indf = tag1[1:].index('f') + 1
            if 'n' in tag1[indf:]:
                tag1 = tag1[indf + 1:]
                p1 = p1[indf + 1:]
                if '的' in p1[0] or 'p' == tag1[0]:
                    del p1[0]
                    del tag1[0]
        # 去除介词引导的宾语补足语
        if 'p' in tag2:
            indp = []
            for i, t in enumerate(tag2):
                if 'p' in t:
                    indp.append(i)
            if indp[-1] > 0 and (
                    'a' in tag2[indp[-1] - 1] or ('n' in tag2[:indp[-1] - 1] and 'v' in tag2[:indp[-1] - 1])):
                tag2 = tag2[:indp[-1]]
                p2 = p2[:indp[-1]]
        return [''.join(p1), ''.join(p2)]

    # 分割名词、谓语成分的归属规则。顺承、倒装、穿插
    def devivedRule(self, wordp, tagp, wordl, tagl):
        global suf, pre
        if 'c' in tagp:
            for i,t in enumerate(tagp):
                if 'c'==t and wordp[i] in self.he:
                    pre = self.devivedSentence(wordp, tagp)
                    break
                else:
                    pre = self.devivedComp(wordp, tagp)
        else:
            pre = self.devivedComp(wordp, tagp)
        if 'c' in tagl:
            for i, t in enumerate(tagl):
                if 'c' == t and wordl[i] in self.he:
                    suf = self.devivedSentence(wordl, tagl)
                    break
                else:
                    suf = self.devivedComp(wordl, tagl)
        else:
            suf = self.devivedComp(wordl, tagl)
        if self.loc == 1:
            suf.extend(pre)
            return suf
        pre.extend(suf)
        return pre

    # 句法成分分析提取
    def analysis(self, content: dict) -> list:
        self.ininfo(content)
        words, tags = self.preData()
        wordp, tagp, wordl, tagl = self.getArea(words, tags)
        wordp, tagp = self.merge(wordp, tagp)
        wordl, tagl = self.merge(wordl, tagl)

        wordp, tagp = self.remove(wordp, tagp)
        wordl, tagl = self.remove(wordl, tagl)

        wordp, tagp = self.merges(wordp, tagp)
        wordl, tagl = self.merges(wordl, tagl)

        wordp, tagp, wordl, tagl = self.adjustloc(wordp, tagp, wordl, tagl)
        # 成分提取、分割
        ans = self.devivedRule(wordp, tagp, wordl, tagl)
        ans.insert(2, self.cent)
        # 获取结果成分
        return ans

    # 获取词在文本中的位置
    def getLoc(self, mode: str, word: str) -> list:
        tags = ['原因中的核心名词', '原因中的谓语或状态', '中心词', '结果中的核心名词', '结果中的谓语或状态']
        start, end = 0, 0
        if len(word) < 1:
            return []
        if mode == tags[2]:
            start = self.indt
            end = start + len(word) - 1
        elif (mode in tags[:2] and self.loc == 0) or (mode in tags[3:] and self.loc == 1):
            temp = self.getStrInd(word, self.text[:self.indt], seq=True)
            start, end = self.indt - temp[1] - 1, self.indt - temp[0] - 1
        elif (mode in tags[3:] and self.loc == 0) or (mode in tags[:2] and self.loc == 1):
            temp = self.getStrInd(word, self.text[self.indt + 1:])
            start, end = self.indt + temp[0] + 1, self.indt + temp[1] + 1
        return [start, end]

    # 获取词在文本中的位置
    def getLocs(self, mode: str, word: str) -> list:
        if ';' in word:
            start, end = [], []
            wordls = word.split(';')
            for ws in wordls:
                temp = self.getLoc(mode, ws)
                if len(temp) != 2:
                    start.append(-1)
                    end.append(-1)
                else:
                    start.append(temp[0])
                    end.append(temp[1])
            return [start, end]
        else:
            return self.getLoc(mode, word)

    # 区域相似字符串匹配
    def getStrInd(self, word: str, text: str, seq=False) -> list:
        start, end = 0, 0
        if seq:
            word = word[::-1]
            text = text[::-1]
        for i in range(len(word)):
            temp = word[:len(word) - i]
            if temp in text:
                start = text.index(temp)
                suf = len(word) - len(temp)
                if suf == 0:
                    end = start + len(temp) - 1
                    return [start, end]
                else:
                    end = start + len(temp) + self.getStrInd(word[len(temp):], text[start + len(temp):])[1]
        return [start, end]

    # 生成ans列表
    def getAns(self, content: dict) -> list:
        tags = ['原因中的核心名词', '原因中的谓语或状态', '中心词', '结果中的核心名词', '结果中的谓语或状态']
        ans = []
        anly = self.analysis(content)
        for i, j in zip(tags, anly):
            temp = [i, j]
            temp.extend(self.getLocs(i, j))
            ans.append(temp)
        return ans

    # 输出格式化
    def outputF(self, ans: list, content: dict) -> dict:
        content['document'][0] = {'text': content['document'][0]['text']}
        qas0 = []
        for item in ans:
            if len(item) == 4:
                qas0.append({"question": item[0], "answers": [{"text": item[1], "start_block": "0", "start": item[2],
                                                               "end_block": "0", "end": item[3]}]})
            else:
                qas0.append({"question": item[0], "answers": []})
        content['qas'][0] = qas0
        return content

    def predict(self, content: dict) -> dict:
        """
        输入标注格式，已转为dict
        输出同标注格式，dict格式
        :param content 标注格式，见样例:
        :return str:
        """
        ans = self.getAns(content)
        content = self.outputF(ans, content)
        return content


if __name__ == "__main__":
    example_input = '{"document": [{"block_id": "0", "text": "08年4月，郑煤集团拟以非公开发行的方式进行煤炭业务整体上市，解决与郑州煤电同业竞争问题，但之后由于股市的大幅下跌导致股价跌破发行价而被迫取消整体上市。"}], "key": "79c29068d30a686", "qas": [[{"question": "中心词", "answers": [{"start_block": "0", "start": 57, "end_block": "0", "end": 58, "text": "导致", "sub_answer": null}]}]]}'
    example_output = '{"document": [{"block_id": "0", "text": "08年4月，郑煤集团拟以非公开发行的方式进行煤炭业务整体上市，解决与郑州煤电同业竞争问题，但之后由于股市的大幅下跌导致股价跌破发行价而被迫取消整体上市。"}], "key": "79c29068d30a686", "qas": [[{"question": "原因中的核心名词", "answers": [{"start_block": "0", "start": 50, "end_block": "0", "end": 51, "text": "股市", "sub_answer": null}]}, {"question": "原因中的谓语或状态", "answers": [{"start_block": "0", "start": 53, "end_block": "0", "end": 56, "text": "大幅下跌", "sub_answer": null}]}, {"question": "中心词", "answers": [{"start_block": "0", "start": 57, "end_block": "0", "end": 58, "text": "导致", "sub_answer": null}]}, {"question": "结果中的核心名词", "answers": [{"start_block": "0", "start": 59, "end_block": "0", "end": 60, "text": "股价", "sub_answer": null}]}, {"question": "结果中的谓语或状态", "answers": [{"start_block": "0", "start": 61, "end_block": "0", "end": 65, "text": "跌破发行价", "sub_answer": null}]}]]}'

    content = json.loads(example_input)
    obj = Predictor()
    output = obj.predict(json.loads(example_input))
    print(output != json.loads(example_output))

